﻿using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using monitor_2_DBwork;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Text;
using Timer = System.Threading.Timer;

namespace ServerLib.Entities
{
    public static class BizssControl
    {
        private const string DelayOptionName = "BizssControlDelay";
        private const string EnablerOptionName = "BizssControlEnabled";
        private const string BIZSSDllName = "izmer_bizss.dll";
        private static int _delayValue;
        private static bool _enabledControl;
        private static bool _initialized;
        private static Timer _timer;
        private static Dictionary<IPAddress, List<IPAddress>> _deviceList;
        private static DllUnmanagedWork _bizss;
        private static Thread _bizssControlThread;
        private static ThreadOptions _threadOptions = new ThreadOptions();
        private class ThreadOptions
        {
            public ThreadOptions()
            {
                IsStopped = true;
                IsStopRequeseted = false;
                IsTimerCounting = false;
            }
            public bool IsStopped { get; set; }
            public bool IsStopRequeseted { get; set; }
            public bool IsTimerCounting { get; set; }
        }

        static BizssControl()
        {
            //
            _initialized = false;
            Initialize();
        }

        public static void Start()
        {
            //Инициализация
            //if(!_initialized)
            //    Initialize();

            if (!_initialized)
                if (!Initialize())
                    return;

            //Запуск контроля
            var d = new ThreadStart(ThreadStart);
            lock (_threadOptions)
            {
                _threadOptions.IsStopped = false;
                _threadOptions.IsStopRequeseted = false;
            }
            _bizssControlThread = new Thread(d);
            _bizssControlThread.Start();
        }

        private static void ThreadStart()
        {
            _timer = new Timer(_timer_Tick, null, 0, 0);
        }

        public static void Stop()
        {
            while (true)
            {
                lock (_threadOptions)
                {
                    if (_threadOptions.IsStopped)
                        return;
                    _threadOptions.IsStopRequeseted = true;
                    if (_threadOptions.IsTimerCounting)
                        lock (_timer)
                        {
                            _timer.Change(Timeout.Infinite, 0);
                            _threadOptions.IsStopped = true;
                            return;
                        }
                }
                Thread.Sleep(200);
            }
        }

        public static void Reset()
        {
            _initialized = false;
        }

        private static bool Initialize()
        {

            //Получение значений параметров
            string check = GetOptions();
            if (check != "ok")
            {
                ThreadAbort(check, true);
                return _initialized = false;
            }

            if (!_enabledControl)
            {
                ThreadAbort("", false);
                return _initialized = false;
            }

            //Получение списка ip-адресов
            check = GetDevices();
            if (check != "ok")
            {
                ThreadAbort(check, true);
                return _initialized = false;
            }

            //Инициализация библиотеки
            _bizss = new DllUnmanagedWork(BIZSSDllName, "");
            check = _bizss.Initialize();
            if (check != "ok")
            {
                ThreadAbort(check, true);
                return _initialized = false;
            }
            _initialized = true;
            return true;
        }

        static void _timer_Tick(object sender)
        {
            lock (_threadOptions)
            {
                _threadOptions.IsTimerCounting = false;
            }
            _timer.Change(Timeout.Infinite, Timeout.Infinite);
            //Server.NIcon.ShowBalloonTip(2000, "WHOOP", "WHOOP", ToolTipIcon.Error);
            ControlWork();
            
            lock (_threadOptions)
            {
                _threadOptions.IsTimerCounting = true;
                if (_threadOptions.IsStopRequeseted)
                {
                    _timer.Change(Timeout.Infinite, Timeout.Infinite);
                    _threadOptions.IsStopped = true;
                    Server.WriteToLog(Server.Rm.GetString("BizssControlOperationComplete"), ServerCategories.Info);
                    return;
                }
                _timer.Change(_delayValue, 0);
            }
            //Server.WriteToLog(Server.Rm.GetString("BizssControlOperationComplete"), ServerCategories.Info);
            Server.OnBizssControlComplete();
        }

        //Контроль параметров нормы и эталона в области
        static void ControlWork()
        {
            foreach (var headDev in _deviceList)
            {
                string etalonParams = _bizss.GetParams(headDev.Key.ToString());
                if(etalonParams.Contains("err:"))
                    continue;
                string etalonValue = GetControlValues(etalonParams);
                foreach (var dev in headDev.Value)
                {
                    string devip = dev.ToString();
                    string pars = _bizss.GetParams(devip);
                    if (pars.Contains("err:"))
                    {
                        //MessageBox.Show("PARS WHOOP!!!\r\n" + pars + " - " + devip);
                        continue;
                    }
                    string value = GetControlValues(pars);
                    if (!value.Equals(etalonValue))
                    {
                        
                        string rr = _bizss.SetParams(devip, etalonValue);
                        DBwork.AddIzmerStatisticsRecord("0," + value, "0," + etalonValue, System.DateTime.Now, devip);
                        if (rr != "ok")
                            MessageBox.Show("SET WHOOP!!!\r\n" + rr + " - " + devip);
                    }
                }
            }
        }

        static void ThreadAbort(string message, bool errors/*, bool stopThread*/)
        {
            if (errors)
                Server.WriteToLog(message.Contains("err:") ? message.Substring(4) : message, ServerCategories.Warning);
            //if (stopThread)
            //    Thread.CurrentThread.Abort();
        }

        /// <summary>
        /// Получает интервал между запусками проверки параметров БИЗСС
        /// </summary>
        /// <returns>
        /// -1 - ошибка при обращении к БД;
        /// -2 - не удается определить значение параметра;
        /// -3 - в БД нет зпрошенного параметра.</returns>
        static string GetOptions()
        {
            string optionsStr = DBwork.GetOptionsList();
            if (optionsStr.Contains("err:"))
            {
                _delayValue = -1;
                return optionsStr;
            }
            var options = optionsStr.Split(';');
            bool delay = false, enabler = false;
            foreach (string option in options)
            {
                var split = option.Split(':');
                if (split[0] == DelayOptionName)
                {
                    int ret;
                    if (int.TryParse(split[1], out ret))
                    {
                        _delayValue = ret * 1000;
                        delay = true;
                        continue;
                    }
                    return "err:" + Server.Rm.GetString("ValueDefinitionError") + " - " + Server.Rm.GetString("BizssControlDelay");
                }
                if (split[0] == EnablerOptionName)
                {
                    bool ret;
                    if (bool.TryParse(split[1], out ret))
                    {
                        _enabledControl = ret;
                        enabler = true;
                        continue;
                    }
                    return "err:" + Server.Rm.GetString("ValueDefinitionError") + " - " + Server.Rm.GetString("BizssControlEnabler");
                }
            }
            if (!delay)
                return "err:" + Server.Rm.GetString("ValueSearchError") + " - " + Server.Rm.GetString("BizssControlDelay");
            if(!enabler)
                return "err:" + Server.Rm.GetString("ValueSearchError") + " - " + Server.Rm.GetString("BizssControlEnabler");
            return "ok";
        }

        /// <summary>
        /// Формирует список адресов (область -> адреса БИЗСС области)
        /// </summary>
        /// <returns></returns>
        static string GetDevices()
        {
            _deviceList = new Dictionary<IPAddress, List<IPAddress>>();
            TreeNode[] oblastList =  DBwork.GetTree();
            if (oblastList[0].Name.Contains("err:"))
            {
                return oblastList[0].Name;
            }
            foreach (var obl in oblastList)
            {
                string mainRtps = obl.Tag.ToString();
                IPAddress mainIp = null;
                var ipList = new List<IPAddress>();
                foreach (TreeNode rtps in obl.Nodes)
                {
                    bool containsIp = false;
                    bool active = false;
                    IPAddress ip = null;
                    foreach (var dev in rtps.Nodes.Cast<TreeNode>().Where(dev => dev.Text == @"БИЗСС"))
                    {
                        var pars = ((string) dev.Tag).Split(';');
                        bool.TryParse(pars[1], out active);
                        if (IPAddress.TryParse(pars[0], out ip))
                            containsIp = true;
                        break;
                    }
                    if(active)
                        if (containsIp)
                        {
                            if (rtps.Text == mainRtps)
                            {
                                mainIp = ip;
                            }
                            else
                            {
                                ipList.Add(ip);
                            }
                        }
                }
                if (mainIp != null)
                {
                    //_deviceList[mainIp] = new List<IPAddress>();
                    _deviceList[mainIp] = ipList;
                }
                else
                {
                    //Server.NIcon.ShowBalloonTip(2000, Server.Rm.GetString("Warning"),Server.Rm.GetString("NoMainIpForOblast") + ":" + obl.Text,ToolTipIcon.Warning);
                    ThreadAbort(Server.Rm.GetString("NoMainIpForOblast") + ": " + obl.Text, true);
                }
            }
            return "ok";
        }

        static string GetControlValues(string str)
        {
            var ret = new StringBuilder(9);
            string[] pars = str.Split(';');
            foreach (var par in pars)
            {
                if(par.Length < 1)
                    continue;
                string[] split = par.Split(':');
                if (split[0] == "Эталон")
                    ret.Append(split[1].Substring(2));
                if(split[0] == "Норма")
                    foreach (var ch in split[1])
                    {
                        int i;
                        if (int.TryParse(ch.ToString(CultureInfo.InvariantCulture), out i))
                        {
                            ret.Append(ch);
                        }
                    }
            }
            return ret.ToString();
        }
    }
}